#include "calc.h"
#include <algorithm>
#include <ctime>
#include <cmath>
#include <cstdlib>

using namespace std;

const int MAX_BIT = 60;

void calc::startCalc() {
	try {
		convstr = singleCalc(convstr);
		convstr = doubleCalc(convstr);
		delBracket(convstr);
		maprep["ans"] = convstr;
		result_d=atof(convstr.c_str());
		outHis();
		outLog("calc finished!");
	} catch (...) {
		throw;
	}
}

string calc::singleCalc(string str) {
	try {
		int pos;
		vector<string> temp;
		for (vector<string>::iterator p = shortSym.begin(); p != shortSym.end(); ++p) {
			int t;
			while ((pos = str.find(*p)) != string::npos) {
				++pos;
				getArgc(pos, str,temp, t);
				str.erase(pos-1,t+2);
				str.insert(pos - 1, calcMode(*p, temp));
			}
		}
		return doubleCalc(str);
	} catch (...) {
		throw;
	}
}


void calc::delBracket(string& str) {
	try {
		while (str[0] == '(') {
			str.erase(str.end() - 1);
			str.erase(str.begin());
		}
	} catch (...) {
		throw;
	}
}


string calc::calcMode(string met, vector<string> arg) {
	try {
		vector<long double> argnum;
		for (vector<string>::iterator p = arg.begin(); p != arg.end(); ++p) {
			*p = singleCalc(*p);
			delBracket(*p);
			argnum.push_back(atof(p->c_str()));
		}
		char temp[MAX_BIT];
		if (met == "A") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", fabs(argnum[0]));
#else
			sprintf(temp, "%g", fabs(argnum[0]));
#endif
		} else if (met=="B") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", ceil(argnum[0]));
#else
			sprintf(temp, "%g", ceil(argnum[0]));
#endif
		} else if (met == "C") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", floor(argnum[0]));
#else
			sprintf(temp, "%g", floor(argnum[0]));
#endif
		} else if (met == "D") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", sqrt(argnum[0]));
#else
			sprintf(temp, "%g", sqrt(argnum[0]));
#endif
		} else if (met == "E") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", pow(argnum[0],argnum[1]));
#else
			sprintf(temp, "%g", pow(argnum[0],argnum[1]));
#endif
		} else if (met == "F") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", cos(argnum[0]));
#else
			sprintf(temp, "%g", cos(argnum[0]));
#endif
		} else if (met == "G") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", sin(argnum[0]));
#else
			sprintf(temp, "%g", sin(argnum[0]));
#endif
		} else if (met == "H") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", tan(argnum[0]));
#else
			sprintf(temp, "%g", tan(argnum[0]));
#endif
		} else if (met == "I") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", acos(argnum[0]));
#else
			sprintf(temp, "%g", acos(argnum[0]));
#endif
		} else if (met == "J") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", asin(argnum[0]));
#else
			sprintf(temp, "%g", asin(argnum[0]));
#endif
		} else if (met == "K") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", atan(argnum[0]));
#else
			sprintf(temp, "%g", atan(argnum[0]));
#endif
		} else if (met == "L") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", atan2(argnum[0],argnum[1]));
#else
			sprintf(temp, "%g", atan2(argnum[0],argnum[1]));
#endif
		} else if (met == "M") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", sinh(argnum[0]));
#else
			sprintf(temp, "%g", sinh(argnum[0]));
#endif
		} else if (met == "N") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", cosh(argnum[0]));
#else
			sprintf(temp, "%g", cosh(argnum[0]));
#endif
		} else if (met == "O") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", tanh(argnum[0]));
#else
			sprintf(temp, "%g", tanh(argnum[0]));
#endif
		} else if (met == "P") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", exp(argnum[0]));
#else
			sprintf(temp, "%g", exp(argnum[0]));
#endif
		} else if (met == "Q") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", log(argnum[0]));
#else
			sprintf(temp, "%g", log(argnum[0]));
#endif
		} else if (met == "R") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", log10(argnum[0]));
#else
			sprintf(temp, "%g", log10(argnum[0]));
#endif
		} else if (met == "S") {
			long double t;
#ifdef _MSC_VER
			sprintf_s(temp, "%g", modf(argnum[0],&t));
#else
			sprintf(temp, "%g", modf(argnum[0],&t));
#endif
		} else if (met == "T") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", fmod(argnum[0],argnum[1]));
#else
			sprintf(temp, "%g", fmod(argnum[0],argnum[1]));
#endif
		} else if (met == "U") {
#ifdef _MSC_VER
			sprintf_s(temp, "%g", ldexp(argnum[0],int(argnum[1])));
#else
			sprintf(temp, "%g", ldexp(argnum[0],int(argnum[1])));
#endif
		} else if(met=="V"){
			int argCount = argnum.size();
			long double avg(0);
			for (int i = 0; i < argCount; ++i) {
				avg += argnum[i];
			}
			avg /= argCount;
#ifdef _MSC_VER
			sprintf_s(temp, "%g",avg);
#else
			sprintf(temp, "%g", avg);
#endif
		} else if (met == "W") {
			long double sum(0);
			for (vector<long double>::iterator p = argnum.begin(); p != argnum.end();++p) {
				sum += *p;
			}
#ifdef _MSC_VER
			sprintf_s(temp, "%g", sum);
#else
			sprintf(temp, "%g", sum);
#endif
		} else if (met == "X") {
			int argCount = argnum.size();
			long double avg(0);
			long double avg2(0);
			for (int i = 0; i < argCount; ++i) {
				avg += argnum[i];
				avg2 += argnum[i] * argnum[i];
			}
			avg /= argCount;
			avg2 /= argCount;
#ifdef _MSC_VER
			sprintf_s(temp, "%g", avg2-avg*avg);
#else
			sprintf(temp, "%g",avg2-avg*avg );
#endif
		} else if (met == "Y") {
			int argCount = argnum.size();
			long double avg(0);
			long double avg2(0);
			for (int i = 0; i < argCount; ++i) {
				avg += argnum[i];
				avg2 += argnum[i] * argnum[i];
			}
			avg /= argCount;
			avg2 /= argCount;
#ifdef _MSC_VER
			sprintf_s(temp, "%g", (avg2 - avg*avg)/argCount*(argCount-1));
#else
			sprintf(temp, "%g", (avg2 - avg*avg)/argCount*(argCount-1));
#endif
		} else if (met == "Z") {
			int argCount = argnum.size();
			long double avg(0);
			long double avg2(0);
			for (int i = 0; i < argCount; ++i) {
				avg += argnum[i];
				avg2 += argnum[i] * argnum[i];
			}
			avg /= argCount;
			avg2 /= argCount;
#ifdef _MSC_VER
			sprintf_s(temp, "%g",sqrt( avg2 - avg*avg));
#else
			sprintf(temp, "%g", sqrt(avg2 - avg*avg));
#endif
		} else if (met == "`") {
			int argCount = argnum.size();
			long double avg(0);
			long double avg2(0);
			for (int i = 0; i < argCount; ++i) {
				avg += argnum[i];
				avg2 += argnum[i] * argnum[i];
			}
			avg /= argCount;
			avg2 /= argCount;
#ifdef _MSC_VER
			sprintf_s(temp, "%g",sqrt ((avg2 - avg*avg) / argCount*(argCount - 1)));
#else
			sprintf(temp, "%g", sqrt((avg2 - avg*avg) / argCount*(argCount - 1)));
#endif
		} else if (met == "~") {
			sort(argnum.begin(), argnum.end());
#ifdef _MSC_VER
			sprintf_s(temp, "%g", argnum.size() % 2 == 0 ? (argnum[argnum.size() / 2] + argnum[argnum.size() / 2 - 1]) / 2 : argnum[argnum.size() / 2]);
#else
			sprintf(temp, "%g",argnum.size() % 2 == 0 ? (argnum[argnum.size() / 2] + argnum[argnum.size() / 2 - 1]) / 2 : argnum[argnum.size() / 2] );
#endif
		} else if (met == "@") {
			sort(argnum.begin(), argnum.end());
#ifdef _MSC_VER
			sprintf_s(temp, "%g",argnum[0]);
#else
			sprintf(temp, "%g", argnum[0]);
#endif
		} else if (met == "$") {
			sort(argnum.begin(), argnum.end());
#ifdef _MSC_VER
			sprintf_s(temp, "%g", argnum.back());
#else
			sprintf(temp, "%g", argnum.back());
#endif
		} else if(met=="&"){
			srand(clock());
#ifdef _MSC_VER
			sprintf_s(temp, "%g", argnum[0]+rand()%int(argnum[1]-argnum[0]));
#else
			sprintf(temp, "%g", argnum[0]+rand()%int(argnum[1]-argnum[0]));
#endif
		}


		//for more calc method




		return "(" + string(temp) + ")";

	} catch (...) {
		throw;
	}
}


string calc::doubleCalc(string str) {
	try {
		if (str[0] != '#') {
			str.insert(str.begin(), '#');
			str.push_back('#');
		}
		bool isNum(false);
		string temp;
		vector<long double> numSta;
		vector<char> opSta;
		long double a, b;
		char opr;
		char res[MAX_BIT];
		opSta.push_back('#');
		for (string::iterator p = str.begin() + 1; p != str.end(); ++p) {
			if (*p<='9' && *p>='0' || *p == '.') {
				temp.push_back(*p);
				isNum = true;
				continue;
			}
			if (isNum) {
				numSta.push_back(atof(temp.c_str()));
				temp.clear();
				isNum = false;
			}
			if (op[opIndex[opSta.back()]][opIndex[*p]] == '1') {
				while (op[opIndex[opSta.back()]][opIndex[*p]] == '1') {
					b = getLast(numSta);
					a = getLast(numSta, 2);
					opr = opSta.back();
					opSta.pop_back();
					numSta.pop_back();
					numSta.pop_back();
					switch (opr) {
					case '+':
						numSta.push_back(a + b);
						break;
					case '-':
						numSta.push_back(a - b);
						break;
					case '*':
						numSta.push_back(a*b);
						break;
					case '/':
						numSta.push_back(a / b);
						break;
					case '%':
						numSta.push_back(int(a) % int(b));
						break;
					case '^':
						numSta.push_back(pow(a, b));
						break;
					case '!':
						numSta.push_back(jec(int(a)));
						break;
					case 'e':
						numSta.push_back(a*pow(10, b));
						break;
					case '(':
						numSta.push_back(a);
						numSta.push_back(b);
						goto lab1;
						break;
					case ')':
						numSta.push_back(a);
						numSta.push_back(b);
						break;
					case '#':
						sprintf_s(res, "%g", b);
						return "(" + string(res) + ")";
						break;
					default:
						break;
					}
				}
			}
			if (*p != ')') {
				opSta.push_back(*p);
			}
		lab1:;
		}
		return "";
	} catch (...) {
		throw;
	}
}


long double calc::jec(int t) {
	try {
		long double s = 1.0;
		for (int i = t; i > 1; --i) {
			s *= i;
		}
		return s;
	} catch (...) {
		throw;
	}
}


long double calc::getLast(vector<long double>& vec, int t /* =1 */) {
	try {
		if (t == 1) {
			if (vec.empty()) {
				vec.push_back(0);
			}
			return vec.back();
		} else {
			if (vec.size() < 2) {
				vec.insert(vec.begin(), 0);
				vec.insert(vec.begin(), 0);
			}
			return *(vec.end() - 2);
		}
	} catch(...){
		throw;
	}
}